
package com.xuexiang.xui_lib.component.button.switchbutton;

import com.xuexiang.xui_lib.component.button.switchbutton.attrs.SwitchAttrSet;
import com.xuexiang.xui_lib.util.AttrValue;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.*;
import ohos.agp.render.Canvas;
import ohos.agp.render.MaskFilter;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.TouchEvent;

/**
 * SwitchButton.
 */
public class SwitchButton extends Button implements Component.DrawTask, Component.LayoutRefreshedListener,
    Component.EstimateSizeListener, Component.TouchEventListener {
    private final int DEFAULT_WIDTH = (int) vp2px(52);
    private final int DEFAULT_HEIGHT = (int) vp2px(36);
    private final int MATERIAL_DEFAULT_WIDTH = (int) vp2px(88);
    private final int MATERIAL_DEFAULT_HEIGHT = (int) vp2px(60);
    /**
     * 阴影半径
     */
    private int shadowRadius;
    /**
     * 阴影Y偏移px
     */
    private int shadowOffset;
    /**
     * 阴影颜色
     */
    private int shadowColor;

    /**
     * 背景半径
     */
    private float mViewRadius;
    /**
     * 按钮半径
     */
    private float buttonRadius;

    /**
     * 背景高
     */
    private float mHeight;

    /**
     * 背景位置
     */
    private float left;
    private float top;
    private float right;
    private float bottom;
    private float centerY;

    /**
     * 背景关闭颜色
     */
    private int uncheckColor;
    /**
     * 背景打开颜色
     */
    private int checkedColor;
    /**
     * 边框宽度px
     */
    private int borderWidth;

    /**
     * Color for button when it's uncheck
     */
    private int uncheckButtonColor;
    /**
     * Color for button when it's check
     */
    private int checkedButtonColor;
    /**
     * Color for button when it's pressed
     */
    private int pressedButtonColor;

    /**
     * Color for border
     */
    private int borderColor;

    /**
     * 按钮最左边
     */
    private float buttonMinX;
    /**
     * 按钮最右边
     */
    private float buttonMaxX;

    /**
     * 按钮当前位置
     */
    private float buttonX;

    /**
     * 阴影画笔
     */
    private Paint shadowPaint;
    /**
     * 背景画笔
     */
    private Paint paint;
    /**
     * 文字画笔
     */
    private Paint textPaint;

    private AnimatorValue valueAnimator;

    private Component mComponent;

    /**
     * 是否选中
     */
    private boolean isChecked;

    /**
     * 是否启用动画
     */
    private boolean isEnableEffect;

    /**
     * 是否启用阴影效果
     */
    private boolean isShadowEffect;

    /**
     * 是否按下
     */
    private boolean isTouchDown = false;

    private boolean isUiInited = false;

    private OnCheckedChangeListener onCheckedChangeListener;

    /**
     * 样式类型
     */
    private int mStyleType = 1;

    private static final int STYLE_NORMAL = 1;
    private static final int STYLE_MATERIAL = 2;
    private static final int STYLE_IOS = 3;

    /**
     * 动画状态：
     * 0.静止
     * 1.拖动-复位
     * 2.拖动-切换
     * 3.点击切换
     **/
    private static final int ANIMATE_STATE_NONE = 0;
    private static final int ANIMATE_STATE_PENDING_RESET = 1;
    private static final int ANIMATE_STATE_PENDING_SETTLE = 2;
    private static final int ANIMATE_STATE_SWITCH = 3;

    /**
     * 绘制矩形区域
     */
    RectFloat mThumbRectF;
    RectFloat mBackRectF;
//    RectFloat mSafeRectF;

    /**
     * 动画状态
     */
    private int animateState = ANIMATE_STATE_NONE;

    private float startX;
    private float startProgress;
    private float progress;

    private long mAnimationDuration;

    private boolean isCancel = false;

    public SwitchButton(Context context) {
        super(context);
        init(context, null);
    }

    public SwitchButton(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public SwitchButton(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    public void setBackColor(Color color) {
        uncheckButtonColor = color.getValue();
    }

    public Color getBackColor() {
        return new Color(uncheckColor);
    }

    public void setThumbColor(Color color) {
        checkedButtonColor = color.getValue();
    }

    public Color getThumbColor() {
        return new Color(checkedButtonColor);
    }


    @Override
    public final void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(0, 0, 0, 0);
    }

    private void initNormal(Context context, AttrSet attrs) {
        AttrValue.get(attrs, SwitchAttrSet.SHADOW_EFFECT, false);
        isShadowEffect = AttrValue.get(attrs, SwitchAttrSet.SHADOW_EFFECT, false);
        uncheckButtonColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_BUTTON_COLOR, new Color(0xFFEEEEEE).getValue());
        checkedButtonColor = AttrValue.get(attrs, SwitchAttrSet.CHECKED_BUTTON_COLOR, new Color(0xFF2B9EE3).getValue());
        pressedButtonColor = AttrValue.get(attrs, SwitchAttrSet.PRESSED_BUTTON_COLOR, new Color(0xFF98CEEE).getValue());
        borderWidth = AttrValue.get(attrs, SwitchAttrSet.BORDER_WIDTH, AttrHelper.vp2px(2, context));
        uncheckColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_COLOR, new Color(0xFFD0D5D8).getValue());
        checkedColor = AttrValue.get(attrs, SwitchAttrSet.CHECK_COLOR, new Color(0xFFCAE3F3).getValue());
    }

    private void initIos(Context context, AttrSet attrs) {
        isShadowEffect = AttrValue.get(attrs, SwitchAttrSet.SHADOW_EFFECT, true);
        uncheckColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_COLOR, new Color(0xFFFDFDFD).getValue());
        checkedColor = AttrValue.get(attrs, SwitchAttrSet.CHECK_COLOR, new Color(0xFF2B9EE3).getValue());
        int buttonColor = AttrValue.get(attrs, SwitchAttrSet.BUTTON_COLOR, new Color(0xFFFEFEFE).getValue());
        borderColor = buttonColor - 0x00202020;
        uncheckButtonColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_BUTTON_COLOR, buttonColor);
        checkedButtonColor = AttrValue.get(attrs, SwitchAttrSet.CHECKED_BUTTON_COLOR, buttonColor);
        borderWidth = AttrValue.get(attrs, SwitchAttrSet.BORDER_WIDTH, AttrHelper.vp2px(1, context));
    }

    private void initMaterial(Context context, AttrSet attrs) {
        isShadowEffect = AttrValue.get(attrs, SwitchAttrSet.SHADOW_EFFECT, false);
        uncheckButtonColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_BUTTON_COLOR, new Color(0xFFEEEEEE).getValue());
        checkedButtonColor = AttrValue.get(attrs, SwitchAttrSet.CHECKED_BUTTON_COLOR, new Color(0xFF2B9EE3).getValue());
        pressedButtonColor = AttrValue.get(attrs, SwitchAttrSet.PRESSED_BUTTON_COLOR, new Color(0xFF98CEEE).getValue());
        borderWidth = AttrValue.get(attrs, SwitchAttrSet.BORDER_WIDTH, AttrHelper.vp2px(2, context));
        uncheckColor = AttrValue.get(attrs, SwitchAttrSet.UNCHECK_COLOR, new Color(0xFFA6A6A6).getValue());
        checkedColor = AttrValue.get(attrs, SwitchAttrSet.CHECK_COLOR, new Color(0xFFCAE3F3).getValue());
    }

    private void init(Context context, AttrSet attrs) {
        this.setClipEnabled(false);
        mStyleType = AttrValue.get(attrs, SwitchAttrSet.STYLE_TYPE, STYLE_NORMAL);
        switch (mStyleType) {
            case STYLE_IOS:
                initIos(context, attrs);
                break;
            case STYLE_MATERIAL:
                initMaterial(context, attrs);
                break;
            default:
                initNormal(context, attrs);
                break;
        }
        shadowRadius = AttrValue.get(attrs, SwitchAttrSet.SHADOW_RADIUS, AttrHelper.vp2px(2.5f, context));
        shadowOffset = AttrValue.get(attrs, SwitchAttrSet.SHADOW_OFFSET, AttrHelper.vp2px(1.5f, context));
        shadowColor = AttrValue.get(attrs, SwitchAttrSet.SHADOW_COLOR, 0Xff999999);
        mAnimationDuration = AttrValue.get(attrs, SwitchAttrSet.ANIMATION_DURATION, 250);
        isChecked = AttrValue.get(attrs, SwitchAttrSet.CHECKED, false);
        isEnableEffect = AttrValue.get(attrs, SwitchAttrSet.ENABLE_EFFECT, true);
        paint = new Paint();
        shadowPaint = new Paint();

        textPaint = new Paint();
        textPaint.setTextAlign(TextAlignment.CENTER);
        textPaint.setColor(Color.BLACK);

        mThumbRectF = new RectFloat();
        mBackRectF = new RectFloat();
//        mSafeRectF = new RectFloat();

        valueAnimator = new AnimatorValue();
        valueAnimator.setDuration(mAnimationDuration);
        valueAnimator.setLoopedCount(0);
        valueAnimator.setValueUpdateListener(animatorUpdateListener);
        valueAnimator.setStateChangedListener(animatorListener);
        super.setClickable(true);
        this.setPadding(0, 0, 0, 0);
        setEstimateSizeListener(this);
        setLayoutRefreshedListener(this);
        setTouchEventListener(this);
        addDrawTask(this);
        if (!isUiInited) {
            onRefreshed(this);
        }
        reset();
    }

    /**
     * 设置点击状态下按钮的颜色
     *
     * @param color
     */
    public void setPressedButtonColor(int color) {
        pressedButtonColor = color;
    }

    /**
     * 设置关闭状态下按钮的颜色
     *
     * @param color
     */
    public void setUnCheckedButtonColor(int color) {
        uncheckButtonColor = color;
    }

    /**
     * 设置打开状态下按钮的颜色
     *
     * @param color
     */
    public void setCheckedButtonColor(int color) {
        checkedButtonColor = color;
    }

    /**
     * 设置关闭状态背景的颜色
     *
     * @param color
     */
    public void setUnCheckColor(int color) {
        uncheckColor = color;
    }

    /**
     * 设置打开状态背景的颜色
     *
     * @param color
     */
    public void setCheckedColor(int color) {
        checkedColor = color;
    }

    /**
     * 设置按钮阴影的颜色
     *
     * @param color
     */
    public void setShadowColor(int color) {
        shadowColor = color;
    }

    /**
     * 设置阴影半径(单位为VP)
     *
     * @param context
     * @param radius
     */
    public void setShadowRadius(Context context, float radius) {
        shadowRadius = AttrHelper.vp2px(radius, context);
    }


    /**
     * 复位
     */
    public void reset() {
        buttonX = isChecked ? buttonMaxX : buttonMinX;
        progress = isChecked ? 1 : 0;
        startProgress = progress;
        invalidate();
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        final int widthMode = EstimateSpec.getMode(widthEstimateConfig);
        final int heightMode = EstimateSpec.getMode(heightEstimateConfig);

        if (widthMode == EstimateSpec.UNCONSTRAINT
            || widthMode == EstimateSpec.NOT_EXCEED) {
//            widthEstimateConfig = EstimateSpec.getSizeWithMode(DEFAULT_WIDTH, EstimateSpec.PRECISE);
        }
        if (heightMode == EstimateSpec.UNCONSTRAINT
            || heightMode == EstimateSpec.NOT_EXCEED) {
//            heightEstimateConfig = EstimateSpec.getSizeWithMode(DEFAULT_HEIGHT, EstimateSpec.PRECISE);
        }
        return true;
    }

    /**
     * 修改默认尺寸
     *
     * @param component
     * @param width
     * @param height
     */
    public void initDefaultSize(Component component, int width, int height) {
        if (width == 0 || height == 0) {
            switch (mStyleType) {
                case STYLE_NORMAL:
                case STYLE_IOS: {
                    component.setWidth(DEFAULT_WIDTH);
                    component.setHeight(DEFAULT_HEIGHT);
                }
                break;
                case STYLE_MATERIAL: {
                    component.setWidth(MATERIAL_DEFAULT_WIDTH);
                    component.setHeight(MATERIAL_DEFAULT_HEIGHT);
                }
            }
        }
    }

    @Override
    public void onRefreshed(Component component) {
        mComponent = component;
        refresh();
        invalidate();
    }

    private void refresh() {
        int height = mComponent.getHeight();
        int width = mComponent.getWidth();
        initDefaultSize(mComponent, width, height);
        float viewPadding = Math.max(shadowRadius + shadowOffset, borderWidth);
        this.mHeight = height - viewPadding - viewPadding;
        mViewRadius = this.mHeight * .5f;
        buttonRadius = mViewRadius - borderWidth;
        if (mStyleType == STYLE_MATERIAL) {
            buttonRadius = buttonRadius * .5f;
        }
        left = viewPadding;
        top = viewPadding;
        right = width - viewPadding;
        bottom = height - viewPadding;
        centerY = (top + bottom) * .5f;
        buttonMinX = left + mViewRadius;
        buttonMaxX = right - mViewRadius;
        if (isChecked()) {
            setCheckedViewState();
        } else {
            setUncheckViewState();
        }
        isUiInited = true;
        invalidate();
    }

    private void setUncheckViewState() {
        buttonX = buttonMinX;
        paint.setColor(new Color(uncheckButtonColor));
        startProgress = 0;
        progress = 0;
        invalidate();
    }

    private void setCheckedViewState() {
        buttonX = buttonMaxX;
        paint.setColor(new Color(checkedButtonColor));
        startProgress = 1;
        progress = 1;
        invalidate();
    }

    private void drawRoundRect(Canvas canvas,
                               float backgroundRadius,
                               Paint paint) {
        canvas.drawRoundRect(mBackRectF, backgroundRadius, backgroundRadius, paint);
    }

    private void drawButton(Canvas canvas, float x, float y) {

        // 设置阴影
        if (isShadowEffect) {
            setupShadowPaint();
            canvas.drawCircle(x, y, buttonRadius, shadowPaint);
        }

        paint.setColor(new Color(isChecked ? checkedButtonColor : uncheckButtonColor));

        if (mStyleType == STYLE_NORMAL && isTouchDown) {
            paint.setColor(new Color(pressedButtonColor));
        }

        if (isTouchDown && mStyleType == STYLE_MATERIAL) {
            paint.setAlpha(0.5f);
            canvas.drawCircle(x, y, buttonRadius + buttonRadius, paint);
            paint.setAlpha(1);
        }

        mThumbRectF.left = x - buttonRadius;
        mThumbRectF.top = y - buttonRadius;
        mThumbRectF.right = x + buttonRadius;
        mThumbRectF.bottom = y + buttonRadius;

        canvas.drawCircle(x, y, buttonRadius, paint);
    }

    /**
     * 设置阴影属性
     */
    private void setupShadowPaint() {
        shadowPaint.reset();
        shadowPaint.setColor(new Color(shadowColor));
        shadowPaint.setStyle(Paint.Style.FILL_STYLE);
        /**
         * 设置滤镜
         */
        shadowPaint.setMaskFilter(new MaskFilter(10, MaskFilter.Blur.OUTER));
        shadowPaint.setGradientShaderColor(new Color[]{new Color(shadowColor), Color.TRANSPARENT});
    }

    public long getAnimationDuration() {
        return mAnimationDuration;
    }

    public void setAnimationDuration(long animationDuration) {
        mAnimationDuration = animationDuration;
    }

    public Size getBackSize() {
        return new Size((int) (right - left), (int) (bottom - top));
    }

    public float getBackRadius() {
        return mViewRadius;
    }

    public void setBackRadius(float backRadius) {
        mViewRadius = backRadius;
        invalidate();
    }

    /**
     * 设置状态,无动画
     *
     * @param checked
     */
    public void setCheckedImmediately(boolean checked) {
        setChecked(checked, false, true);
    }

    /**
     * 设置状态,不触发监听
     *
     * @param checked
     */
    public void setCheckedNoEvent(boolean checked) {
        setChecked(checked, true, false);
    }

    /**
     * 设置状态,无动画,不触发监听
     *
     * @param checked
     */
    public void setCheckedImmediatelyNoEvent(boolean checked) {
        setChecked(checked, false, false);
    }

    /**
     * 切换状态,不触发监听
     */
    public void toggleNoEvent() {
        toggle(true, false);
    }

    /**
     * 切换状态,无动画不触发监听
     */
    public void toggleImmediatelyNoEvent() {
        toggle(false, false);
    }

    /**
     * 切换状态,无动画
     */
    public void toggleImmediately() {
        toggle(false, true);
    }

    /**
     * 设置状态
     *
     * @param checked
     */
    public void setChecked(boolean checked) {
        setChecked(checked, true, true);
    }

    private void setChecked(boolean checked, boolean isAnimate, boolean isNotify) {
        if (checked == isChecked()) {
            invalidate();
            return;
        }
        toggle(isAnimate, isNotify);
    }

    public boolean isChecked() {
        return isChecked;
    }

    /**
     * 切换状态
     */
    public void toggle() {
        toggle(true, true);
    }

    /**
     * 切换状态
     *
     * @param animate
     * @param isNotify
     */
    private void toggle(boolean animate, boolean isNotify) {
        if (!isEnabled()) {
            return;
        }

        if (!isUiInited) {
            isChecked = !isChecked;
            notifyEvent(isNotify);
            return;
        }
        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }
        if (!isEnableEffect || !animate) {
            isChecked = !isChecked;
            if (isChecked()) {
                setCheckedViewState();
            } else {
                setUncheckViewState();
            }
            notifyEvent(isNotify);
            return;
        }
        animateState = ANIMATE_STATE_SWITCH;
        if (isChecked()) {
            isChecked = false;
            valueAnimator.setDuration((long) (progress * mAnimationDuration));
        } else {
            isChecked = true;
            valueAnimator.setDuration((long) ((1 - progress) * mAnimationDuration));
        }
        startAnimator(isNotify);
    }

    private void startAnimator(boolean isNotify) {
        switch (animateState) {
            case ANIMATE_STATE_PENDING_SETTLE:
            case ANIMATE_STATE_SWITCH: {
                notifyEvent(isNotify);
                break;
            }
            default:
                break;
        }

        startProgress = progress;
        isCancel = false;
        valueAnimator.start();
    }

    private void notifyEvent(boolean isNotify) {
        if (onCheckedChangeListener != null && isNotify) {
            onCheckedChangeListener.onCheckedChanged(this, isChecked());
        }
    }

    /**
     * 是否显示按钮阴影
     *
     * @param shadowEffect
     */
    public void setShadowEffect(boolean shadowEffect) {
        if (this.isShadowEffect == shadowEffect) {
            return;
        }
        this.isShadowEffect = shadowEffect;
    }

    /**
     * 设置是否开启切换动画
     *
     * @param enable true:开启动画；false：关闭动画
     */
    public void setEnableEffect(boolean enable) {
        this.isEnableEffect = enable;
    }

    /**
     * 动画-设置新的状态
     */
    private void pendingSettleState() {
        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }
        if (isChecked()) {
            valueAnimator.setDuration((long) (progress * mAnimationDuration));
        } else {
            valueAnimator.setDuration((long) ((1 - progress) * mAnimationDuration));
        }
        startAnimator(true);
    }

    /**
     * 设置值改变监听
     *
     * @param listener 选中状态回调监听
     */
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        onCheckedChangeListener = listener;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        // 绘制不同风格按钮
        switch (mStyleType) {
            case STYLE_NORMAL:
                drawStyleNormal(component, canvas);
                break;
            case STYLE_MATERIAL:
                drawStyleMaterial(component, canvas);
                break;
            case STYLE_IOS:
                drawStyleIos(component, canvas);
                break;
            default:
                break;
        }
    }

    private void drawStyleNormal(Component component, Canvas canvas) {
        paint.setAlpha(1);
        paint.setStrokeWidth(borderWidth);
        paint.setStyle(Paint.Style.FILL_STYLE);

        mBackRectF.left = left;
        mBackRectF.top = top;
        mBackRectF.right = right;
        mBackRectF.bottom = bottom;

        // 绘制未开启背景
        paint.setColor(new Color(uncheckColor));
        drawRoundRect(canvas, mViewRadius, paint);

        // 绘制开启背景
        paint.setColor(new Color(checkedColor));
        paint.setAlpha(progress);
        paint.setStyle(Paint.Style.FILL_STYLE);
        drawRoundRect(canvas, mViewRadius, paint);
        paint.setAlpha(1);

        // 绘制按钮
        drawButton(canvas, buttonX, centerY);
    }

    private void drawStyleMaterial(Component component, Canvas canvas) {
        paint.setAlpha(1);
        paint.setStrokeWidth(borderWidth);
        paint.setStyle(Paint.Style.FILL_STYLE);

        // 绘制未开启背景
        mBackRectF.left = left + mViewRadius;
        mBackRectF.top = top + mViewRadius * .7F;
        mBackRectF.right = right - mViewRadius;
        mBackRectF.bottom = bottom - mViewRadius * .7F;
        paint.setColor(new Color(uncheckColor));

        drawRoundRect(canvas, mViewRadius, paint);

        // 绘制开启背景
        mBackRectF.left = left + mViewRadius;
        mBackRectF.top = top + mViewRadius * .7F;
        mBackRectF.right = left + buttonX;
        mBackRectF.bottom = bottom - mViewRadius * .7F;
        mBackRectF.left = left + mViewRadius;
        paint.setColor(new Color(checkedColor));
        paint.setStyle(Paint.Style.FILL_STYLE);
        drawRoundRect(canvas, mViewRadius, paint);

        // 绘制按钮
        drawButton(canvas, buttonX, centerY);
    }

    private void drawStyleIos(Component component, Canvas canvas) {
        paint.setAlpha(1);
        paint.setStrokeWidth(borderWidth);
        paint.setStyle(Paint.Style.FILL_STYLE);

        // 绘制未开启背景
        paint.setColor(new Color(uncheckColor));

        mBackRectF.left = left;
        mBackRectF.top = top;
        mBackRectF.right = right;
        mBackRectF.bottom = bottom;
        drawRoundRect(canvas, mViewRadius, paint);

        // 绘制关闭状态的边框
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setColor(new Color(borderColor));
        drawRoundRect(canvas, mViewRadius, paint);

        // 绘制开启背景
        paint.setColor(new Color(checkedColor));
        paint.setAlpha(progress);
        paint.setStyle(Paint.Style.FILL_STYLE);
        drawRoundRect(canvas, mViewRadius, paint);
        paint.setAlpha(1);

        // 绘制按钮
        drawButton(canvas, buttonX, centerY);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!isEnabled()) {
            return false;
        }
        int actionMasked = touchEvent.getAction();

        switch (actionMasked) {
            case TouchEvent.PRIMARY_POINT_DOWN: {
                isTouchDown = true;
                if (valueAnimator.isRunning()) {
                    valueAnimator.cancel();
                }
                touchDownTime = System.currentTimeMillis();
                startX = touchEvent.getPointerScreenPosition(0).getX();
                invalidate();
                break;
            }
            case TouchEvent.POINT_MOVE: {
                float eventX = touchEvent.getPointerScreenPosition(0).getX();
                float distance = eventX - startX;
                startX = eventX;
                buttonX = Math.max(buttonMinX, Math.min(buttonMaxX, buttonX + distance));
                progress = (buttonX - buttonMinX) / (buttonMaxX - buttonMinX);
                invalidate();
                break;
            }
            case TouchEvent.CANCEL:
            case TouchEvent.PRIMARY_POINT_UP: {
                float eventX = touchEvent.getPointerScreenPosition(0).getX();
                float distance = eventX - startX;
                isTouchDown = false;
                buttonX = Math.max(buttonMinX, Math.min(buttonMaxX, buttonX + distance));
                progress = (buttonX - buttonMinX) / (buttonMaxX - buttonMinX);
                if (System.currentTimeMillis() - touchDownTime <= 200) {
                    toggle();
                } else {
                    boolean newCheck = progress > .5f;
                    if (newCheck == isChecked()) {
                        animateState = ANIMATE_STATE_PENDING_RESET;
                    } else {
                        isChecked = newCheck;
                        animateState = ANIMATE_STATE_PENDING_SETTLE;
                    }
                    pendingSettleState();
                }
                break;
            }
            default:
                break;
        }
        return true;
    }

    /**
     * 值改变监听器
     */
    public interface OnCheckedChangeListener {
        /**
         * 值改变接口
         *
         * @param view
         * @param isChecked
         */
        void onCheckedChanged(SwitchButton view, boolean isChecked);
    }

    private float vp2px(float vp) {
        return AttrHelper.vp2px(vp, getContext());
    }

    /**
     * 手势按下的时刻
     */
    private long touchDownTime;

    private AnimatorValue.ValueUpdateListener animatorUpdateListener
        = new AnimatorValue.ValueUpdateListener() {
        @Override
        public void onUpdate(AnimatorValue animatorValue, float value) {
            if (isCancel || value == 0) return;

            if (isChecked) {
                progress = startProgress + (1 - startProgress) * value;
            } else {
                progress = startProgress - startProgress * value;
            }

            buttonX = Math.max(buttonMinX, Math.min(buttonMaxX, buttonMinX + (buttonMaxX - buttonMinX) * progress));

            invalidate();
        }
    };

    private AnimatorGroup.StateChangedListener animatorListener = new AnimatorGroup.StateChangedListener() {
        @Override
        public void onStart(Animator animator) {
        }

        @Override
        public void onStop(Animator animator) {
        }

        @Override
        public void onCancel(Animator animator) {
            isCancel = true;
        }

        @Override
        public void onEnd(Animator animator) {
            if (isCancel) {
                return;
            }
            reset();
        }

        @Override
        public void onPause(Animator animator) {
        }

        @Override
        public void onResume(Animator animator) {
        }
    };
}
